home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK2.toast / Development Kits (Disc 2) / QuickTime / Programming Stuff / Documentation / develop articles / develop Issue 14 / Video Digitizing / HackTV & softVdig / HackTV.c < prev    next >
Encoding:
Text File  |  1993-03-18  |  28.1 KB  |  1,151 lines  |  [TEXT/KAHL]

  1. /*
  2.     File:        HackTV.c
  3.  
  4.     Contains:    Hack TV routines.
  5.             
  6.                 Refer to develop Issue 13, "Video Digitizing Under QuickTime",
  7.                 for details on this code.
  8.                 
  9.                 This code requires QuickTime 1.5.
  10.  
  11.     Written by:    Gary Woodcock
  12.  
  13.     Copyright:    © 1992-1993 by Apple Computer, Inc.
  14.  
  15.     Change History (most recent first):
  16.  
  17. */
  18.  
  19. //-----------------------------------------------------------------------
  20. // Includes
  21.  
  22. #include <Menus.h>
  23. #include <Windows.h>
  24. #include <QuickDraw.h>
  25. #include <OSEvents.h>
  26. #include <Resources.h>
  27. #include <Desk.h>
  28. #include <Fonts.h>
  29. #include <ToolUtils.h>
  30. #include <QuickTimeComponents.h>
  31. #include <Scrap.h>
  32. #include <Printing.h>
  33. #include <Errors.h>
  34. #include <SysEqu.h>
  35. #include <Folders.h>
  36. #include <Script.h>
  37. #include <Memory.h>
  38. #include <GestaltEqu.h>
  39.  
  40. #ifndef THINK_C
  41.     #include <Packages.h>
  42. #endif THINK_C
  43.  
  44. #include "softVdig.h"
  45.  
  46. //-----------------------------------------------------------------------
  47. // Constants
  48.  
  49. // Menu bar
  50. enum
  51. {
  52.     kMenuBarID = 128
  53. };
  54.  
  55. // Menus
  56. enum
  57. {
  58.     kAppleID = 128,
  59.     kFileID,
  60.     kEditID,
  61.     kMonitorID
  62. };
  63.  
  64. // Apple menu items
  65. enum
  66. {
  67.     kAboutItem = 1
  68. };
  69.  
  70. // File menu items
  71. enum
  72. {
  73.     kPageSetupItem = 1,
  74.     kPrintItem,
  75.     kQuitItem = 4
  76. };
  77.  
  78. // Edit menu items
  79. enum
  80. {
  81.     kUndoItem = 1,
  82.     kCutItem = 3,
  83.     kCopyItem,
  84.     kPasteItem,
  85.     kClearItem
  86. };
  87.  
  88. // Monitor menu items
  89. enum
  90. {
  91.     kVideoSettingsItem = 1,
  92.     kSoundSettingsItem,
  93.     kQuarterSizeItem = 4,
  94.     kHalfSizeItem,
  95.     kFullSizeItem,
  96.     kRecordItem = 8
  97. };
  98.  
  99. // Dialog IDs
  100. enum
  101. {
  102.     kAboutDLOGID = 128,
  103.     kMonitorDLOGID
  104. };
  105.  
  106. // Common DITL items
  107. enum
  108. {
  109.     kAboutOKButton = 1,
  110.     kAboutOKButtonOutline
  111. };
  112.  
  113. //-----------------------------------------------------------------------
  114. // Globals
  115.  
  116. MenuHandle                gAppleMenu;
  117. MenuHandle                gFileMenu;
  118. MenuHandle                gEditMenu;
  119. MenuHandle                gMonitorMenu;
  120. EventRecord                gTheEvent;
  121. Boolean                    gQuitFlag;
  122. SeqGrabComponent        gSeqGrabber;
  123. SGChannel                gVideoChannel;
  124. SGChannel                gSoundChannel;
  125. WindowPtr                gMonitor;
  126. Rect                    gActiveVideoRect;
  127. PicHandle                gMonitorPICT;
  128. Boolean                    gFullSize;
  129. Boolean                    gHalfSize;
  130. Boolean                    gQuarterSize;
  131. THPrint                    gPrintRec;
  132. AlignmentProcRecordPtr    gSeqGrabberAlignProc;
  133. VideoDigitizerComponent    gVdig;
  134.  
  135. //-----------------------------------------------------------------------
  136. // Prototypes
  137.  
  138. static void
  139. DoInit (void);
  140.  
  141. static void
  142. DoMenuSetup (void);
  143.  
  144. static void
  145. HandleEvent (void);
  146.  
  147. static void
  148. HandleMouseDown    (void);
  149.  
  150. static void
  151. AdjustMenus (void);
  152.  
  153. static void
  154. Enable (Handle menu, short item, Boolean ok);
  155.  
  156. static void
  157. HandleMenu (long menu);
  158.  
  159. static void
  160. DoAboutDialog (void);
  161.  
  162. static void
  163. DoQuit (void);
  164.  
  165. pascal void
  166. AboutDrawProc (DialogPtr theDialog, short theItemNum);
  167.  
  168. static OSErr
  169. XorRectToRgn (Rect *srcRectA, Rect *srcRectB, RgnHandle *destRgn);
  170.  
  171. pascal Boolean
  172. SeqGrabberModalFilterProc (DialogPtr theDialog, EventRecord *theEvent,
  173.     short *itemHit, long refCon);
  174.  
  175. static Boolean
  176. HasQuickTime15 (void);
  177.  
  178. //-----------------------------------------------------------------------
  179.  
  180. main (void)
  181. {
  182.     // Init
  183.     DoInit();
  184.     DoMenuSetup();
  185.     
  186.     // Eat events until done
  187.     do
  188.     {
  189.         HandleEvent();
  190.     }
  191.     while (!gQuitFlag);
  192.     
  193.     // Take off, eh?
  194.     ExitToShell();
  195. }
  196.  
  197. //-----------------------------------------------------------------------
  198.  
  199. static void
  200. DoInit (void)
  201. {
  202.     ComponentDescription    theDesc;
  203.     ComponentResult            result = noErr;
  204.     Component                sgCompID = 0L;
  205.     GrafPtr                    savedPort;
  206.     Component                vdigCompID;            // kck
  207.     
  208.     // Set up quit flag
  209.     gQuitFlag = false;
  210.     
  211.     // MacMantra™
  212.     MaxApplZone();
  213.     InitGraf (&qd.thePort);
  214.     InitFonts();
  215.     FlushEvents (everyEvent, 0);
  216.     InitWindows();
  217.     InitMenus();
  218.     TEInit();
  219.     InitDialogs (0L);
  220.     InitCursor();
  221.     EnterMovies();
  222.     MoreMasters();
  223.     MoreMasters();
  224.     MoreMasters();
  225.     MoreMasters();
  226.     
  227.     // Init stuff
  228.     gSeqGrabber = 0L;
  229.     gVideoChannel = 0L;
  230.     gSoundChannel = 0L;
  231.     gMonitorPICT = nil;
  232.     gPrintRec = (THPrint) NewHandleClear (sizeof (TPrint));
  233.     
  234.     // Find and open a sequence grabber
  235.     theDesc.componentType = SeqGrabComponentType;
  236.     theDesc.componentSubType = 0L;
  237.     theDesc.componentManufacturer = 'appl';
  238.     theDesc.componentFlags = 0L;
  239.     theDesc.componentFlagsMask = 0L;    
  240.     sgCompID = FindNextComponent (nil, &theDesc);
  241.     if (sgCompID != 0L)
  242.     {
  243.         gSeqGrabber = OpenComponent (sgCompID);
  244.     }
  245.     
  246.     // Find the softVdig
  247.     #ifdef DEBUG_IT
  248.         vdigCompID = RegisterSoftVdig();
  249.     #else
  250.         theDesc.componentType = videoDigitizerComponentType;
  251.         theDesc.componentSubType = 'soft';
  252.         theDesc.componentManufacturer = 'jph ';
  253.         theDesc.componentFlags = 0L;
  254.         theDesc.componentFlagsMask = 0L;
  255.         vdigCompID = FindNextComponent (nil, &theDesc);
  256.         SetDefaultComponent (vdigCompID, defaultComponentAnyFlagsAnyManufacturerAnySubType);
  257.     #endif DEBUG_IT
  258.  
  259.     // If we got a sequence grabber, set it up
  260.     if (gSeqGrabber != 0L)
  261.     {
  262.         // Get the monitor
  263.         gMonitor = GetNewDialog (kMonitorDLOGID, nil, (WindowPtr) -1L);
  264.         if (gMonitor != nil)
  265.         {
  266.             // Initialize the sequence grabber
  267.             GetPort (&savedPort);
  268.             SetPort (gMonitor);
  269.             ShowWindow (gMonitor);        
  270.             result = SGInitialize (gSeqGrabber);
  271.             if (result == noErr)
  272.             {
  273.                 result = SGSetGWorld (gSeqGrabber, (CGrafPtr) gMonitor, nil);
  274.                 
  275.                 // Get a video channel
  276.                 result = SGNewChannel (gSeqGrabber, VideoMediaType, &gVideoChannel);
  277.                 if ((gVideoChannel != nil) && (result == noErr))
  278.                 {
  279.                     short    width;
  280.                     short    height;
  281.                     
  282.                     gQuarterSize = false;
  283.                     gHalfSize = true;
  284.                     gFullSize = false;
  285.                     
  286.                     result = SGGetSrcVideoBounds (gVideoChannel, &gActiveVideoRect);
  287.                     width = (gActiveVideoRect.right - gActiveVideoRect.left) / 2;
  288.                     height = (gActiveVideoRect.bottom - gActiveVideoRect.top) / 2;
  289.                     SizeWindow (gMonitor, width, height, false);
  290.                     
  291.                     result = SGSetChannelUsage (gVideoChannel, seqGrabPreview | seqGrabRecord | seqGrabPlayDuringRecord);
  292.                     result = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  293.                 }
  294.                 
  295.                 // Get a sound channel
  296.                 result = SGNewChannel (gSeqGrabber, SoundMediaType, &gSoundChannel);
  297.                 if ((gSoundChannel != nil) && (result == noErr))
  298.                 {
  299.                     if (HasQuickTime15())
  300.                     {
  301.                         // There is a bug in QuickTime 1.5 where a SGChannel of type sound
  302.                         // will return successfully if there is no sound driver present.
  303.                         // To get around this, if we're running QT 1.5, we call 
  304.                         // SGGetSoundInputDriver after a successful SGNewChannel call for
  305.                         // a sound channel to find out if we really got one.  QuickTime
  306.                         // 1.6 has fixed this problem.
  307.                         
  308.                         short    sndDrvrRefNum = SGGetSoundInputDriver (gSoundChannel);
  309.                         
  310.                         if (sndDrvrRefNum == 0)
  311.                         {
  312.                             result = SGDisposeChannel (gSeqGrabber, gSoundChannel);
  313.                             gSoundChannel = nil;
  314.                         }
  315.                     }
  316.                     
  317.                     if (gSoundChannel != nil)
  318.                     {
  319.                         result = SGSetChannelUsage (gSoundChannel, seqGrabPreview | seqGrabRecord);
  320.                         
  321.                         // Set the volume low to prevent feedback when we start the preview,
  322.                         // in case the mic is anywhere near the speaker.
  323.                         result = SGSetChannelVolume (gSoundChannel, 0x0010);
  324.                     }
  325.                 }
  326.                 
  327.                 // Get the alignment proc (for use when dragging the monitor)
  328.                 result = SGGetAlignmentProc (gSeqGrabber, gSeqGrabberAlignProc);
  329.                 
  330.                 // Get ready…
  331.                 // result = SGPrepare (gSeqGrabber, true, true);
  332.             }
  333.             
  334.             // Go!
  335.             if(result == noErr) result = SGStartPreview (gSeqGrabber);
  336.             SetPort (savedPort);
  337.         }
  338.     }
  339. }
  340.  
  341. //-----------------------------------------------------------------------
  342.  
  343. static void
  344. DoMenuSetup (void)
  345. {    
  346.     Handle    theMenuBar = GetNewMBar (kMenuBarID);
  347.     
  348.     // Set up our menus
  349.     SetMenuBar (theMenuBar);
  350.     gAppleMenu = GetMHandle (kAppleID);
  351.     gFileMenu = GetMHandle (kFileID);
  352.     gEditMenu = GetMHandle (kEditID);
  353.     gMonitorMenu = GetMHandle (kMonitorID);
  354.     AddResMenu (gAppleMenu, 'DRVR');
  355.     
  356.     // Last minute adjustments…
  357.     AdjustMenus();
  358. }
  359.  
  360. //-----------------------------------------------------------------------
  361.  
  362. static void
  363. HandleEvent (void)
  364. {
  365.     ComponentResult    result = noErr;
  366.  
  367.     // Do system stuff
  368.     HiliteMenu (0);
  369.     SystemTask();
  370.     
  371.     // Give some time to the sequence grabber
  372.     if (gSeqGrabber != 0L)
  373.         result = SGIdle (gSeqGrabber);
  374.     
  375.     // Suck an event
  376.     if (WaitNextEvent (everyEvent, &gTheEvent, 0, 0))
  377.     {
  378.         // What was it?
  379.         switch (gTheEvent.what)
  380.         {
  381.             case mouseDown:
  382.             {
  383.                 // Handle it
  384.                 HandleMouseDown();
  385.                 break;
  386.             }
  387.             case keyDown:
  388.             case autoKey:
  389.             {
  390.                 char    theChar = gTheEvent.message & charCodeMask;
  391.                 long    theMenu = MenuKey (theChar);
  392.  
  393.                 // Handle menu command keys
  394.                 HandleMenu (theMenu);                
  395.                 break;
  396.             }
  397.             case updateEvt:
  398.             {
  399.                 if ((gMonitor != nil) && ((WindowPtr) (gTheEvent.message) == (WindowPtr) gMonitor))
  400.                 {
  401.                     // Eat the update
  402.                     BeginUpdate (gMonitor);
  403.                     EndUpdate (gMonitor);
  404.                 }
  405.                 break;
  406.             }
  407.             default:    // We don't really care about any other events, but you might, so feel free
  408.             {
  409.                 break;
  410.             }
  411.         }
  412.     }
  413. }
  414.  
  415. //-----------------------------------------------------------------------
  416.  
  417. static void
  418. HandleMouseDown (void)
  419. {    
  420.     WindowPtr    theWindow;
  421.     short        windowCode = FindWindow (gTheEvent.where, &theWindow);
  422.     
  423.     // Where was the mouse down?
  424.     switch (windowCode)
  425.     {
  426.         case inSysWindow:
  427.         { 
  428.             SystemClick (&gTheEvent, theWindow);
  429.             break;
  430.         }
  431.         case inMenuBar:
  432.         {
  433.             AdjustMenus();
  434.             HandleMenu (0L);
  435.             break;
  436.         }
  437.         case inDrag:
  438.         {
  439.             // Was it the monitor?
  440.             if (theWindow == gMonitor)
  441.             {
  442.                 ComponentResult    result = noErr;
  443.                 Rect            limitRect;
  444.                 RgnHandle        grayRgn = GetGrayRgn();
  445.                 Rect            boundsRect;
  446.                 
  447.                 // Find bounds
  448.                 if (grayRgn != nil)
  449.                 {
  450.                     limitRect = (*grayRgn)->rgnBBox;
  451.                 }
  452.                 else
  453.                 {
  454.                     limitRect = qd.screenBits.bounds;
  455.                 }
  456.                 
  457.                 // Pause the sequence grabber
  458.                 result = SGPause (gSeqGrabber, true);
  459.                 
  460.                 if (gVideoChannel != nil)
  461.                 {
  462.                     // Drag it with the totally cool DragAlignedWindow
  463.                       // Note that the sequence grabber can get real confused when you use this
  464.                       // call if you've got multiple video channels - this'll get fixed in the 
  465.                       // next release.  
  466.                       result = SGGetChannelBounds (gVideoChannel, &boundsRect);
  467.                     DragAlignedWindow (theWindow, gTheEvent.where, &limitRect, &boundsRect, gSeqGrabberAlignProc);
  468.                 }
  469.                 else
  470.                 {
  471.                     DragWindow (theWindow, gTheEvent.where, &limitRect);
  472.                 }
  473.                 
  474.                 // Start up the sequence grabber
  475.                 result = SGPause (gSeqGrabber, false);
  476.             }
  477.             break;
  478.         }
  479.         default:
  480.         {
  481.             break;
  482.         }
  483.     }
  484. }
  485.  
  486. //-----------------------------------------------------------------------
  487.  
  488. static void
  489. AdjustMenus (void)
  490. {
  491.     register WindowPeek        wp = nil;
  492.     short                    kind = 0;
  493.     Boolean                    DA = false;
  494.     ComponentResult            result = noErr;
  495.     
  496.     // What kind of window is frontmost?
  497.     wp = (WindowPeek) FrontWindow();
  498.     kind = wp ? wp->windowKind : 0;
  499.     DA = kind < 0;
  500.     
  501.     // Set our menu item states appropriately
  502.     
  503.     // Apple menu
  504.     Enable ((Handle) gAppleMenu, kAboutItem, true);    
  505.     
  506.     // File menu
  507.     Enable ((Handle) gFileMenu, kPageSetupItem, true);
  508.     Enable ((Handle) gFileMenu, kPrintItem, (gVideoChannel != 0L ? true : false));
  509.     Enable ((Handle) gFileMenu, kQuitItem, true);
  510.  
  511.     // Edit menu
  512.     Enable ((Handle) gEditMenu, kUndoItem, DA);
  513.     Enable ((Handle) gEditMenu, kCutItem, DA || (gVideoChannel != 0L));
  514.     Enable ((Handle) gEditMenu, kCopyItem, DA || (gVideoChannel != 0L));
  515.     Enable ((Handle) gEditMenu, kPasteItem, DA);
  516.     Enable ((Handle) gEditMenu, kClearItem, DA);
  517.     
  518.     // Monitor menu
  519.     Enable ((Handle) gMonitorMenu, kVideoSettingsItem, (gVideoChannel != 0L ? true : false));
  520.     Enable ((Handle) gMonitorMenu, kSoundSettingsItem, (gSoundChannel != 0L ? true : false));
  521.     Enable ((Handle) gMonitorMenu, kQuarterSizeItem, (gVideoChannel != 0L ? true : false));
  522.     CheckItem (gMonitorMenu, kQuarterSizeItem, gQuarterSize);
  523.     Enable ((Handle) gMonitorMenu, kHalfSizeItem, (gVideoChannel != 0L ? true : false));
  524.     CheckItem (gMonitorMenu, kHalfSizeItem, gHalfSize);
  525.     Enable ((Handle) gMonitorMenu, kFullSizeItem, (gVideoChannel != 0L ? true : false));
  526.     CheckItem (gMonitorMenu, kFullSizeItem, gFullSize);
  527.     Enable ((Handle) gMonitorMenu, kRecordItem, (gVideoChannel != 0L ? true : false));
  528.     
  529.     // Draw it
  530.     DrawMenuBar();
  531. }
  532.  
  533. //-----------------------------------------------------------------------
  534.  
  535. static void
  536. Enable (Handle menu, short item, Boolean ok)
  537. {
  538.     // Utility routine to enable and disable menu items
  539.     if (ok)
  540.     {
  541.         EnableItem ((MenuHandle) menu, item);
  542.     }
  543.     else
  544.     {
  545.         DisableItem ((MenuHandle) menu, item);
  546.     }
  547. }
  548.  
  549. //-----------------------------------------------------------------------
  550.  
  551. static void
  552. HandleMenu (long theMenu)
  553. {    
  554.     long            mSelect;
  555.     short            menuID;
  556.     short            menuItem;
  557.     ComponentResult    result = noErr;    
  558.     Str255            menuItemStr;
  559.     
  560.     // Did we get a menu?
  561.     if (theMenu == 0L)
  562.     {
  563.         // Nope, get it from menu select
  564.         mSelect = MenuSelect (gTheEvent.where);
  565.     }
  566.     else
  567.     {
  568.         // Yep, use it
  569.         mSelect = theMenu;
  570.     }
  571.     
  572.     // Decode it
  573.     menuID = HiWord (mSelect);
  574.     menuItem = LoWord (mSelect);
  575.     
  576.     // Which menu is it?
  577.     switch (menuID)
  578.     {
  579.         case kAppleID:
  580.         {
  581.             if (menuItem == kAboutItem)
  582.             {
  583.                 // Do the boring about box
  584.                 DoAboutDialog();
  585.             }
  586.             else    // It's a DA
  587.             {
  588.                 Str255    name;
  589.                 GrafPtr    savedPort;
  590.                 
  591.                 // Open the DA
  592.                 GetPort (&savedPort);
  593.                 GetItem (gAppleMenu, menuItem, name);
  594.                 OpenDeskAcc (name);
  595.                 SetPort (savedPort);
  596.             }
  597.             break;
  598.         }
  599.         case kFileID:
  600.         {
  601.             switch (menuItem)
  602.             {
  603.                 case kPageSetupItem:
  604.                 {
  605.                     // Do the page setup dialog
  606.                     PrOpen();
  607.                     PrStlDialog (gPrintRec);
  608.                     PrClose();
  609.                     break;
  610.                 }
  611.                 case kPrintItem:
  612.                 {
  613.                     TPPrPort    printPort;
  614.                     TPrStatus    printStatus;
  615.                     
  616.                     // Copy a frame from the monitor
  617.                     if (gMonitorPICT != nil)
  618.                     {
  619.                         KillPicture (gMonitorPICT);
  620.                     }
  621.                     gMonitorPICT = nil;
  622.                     result = SGGrabPict (gSeqGrabber, &gMonitorPICT, nil, 0, grabPictOffScreen);
  623.                     if ((result == noErr) && (gMonitorPICT != nil))
  624.                     {
  625.                         // Print it
  626.                         HLock ((Handle) gMonitorPICT);
  627.                         PrOpen();
  628.                         if (PrJobDialog (gPrintRec))
  629.                         {
  630.                             printPort = PrOpenDoc (gPrintRec, nil, nil);
  631.                             result = PrError();
  632.                             PrOpenPage (printPort, 0);
  633.                             result = PrError();
  634.                             DrawPicture (gMonitorPICT, &((**gMonitorPICT).picFrame));
  635.                             PrClosePage (printPort);
  636.                             result = PrError();
  637.                             PrCloseDoc (printPort);
  638.                             result = PrError();
  639.                             if ((**gPrintRec).prJob.bJDocLoop == bSpoolLoop)
  640.                             {
  641.                                 PrPicFile (gPrintRec, 0, 0, 0, &printStatus);
  642.                                 result = PrError();
  643.                             }
  644.                         }
  645.                         PrClose();
  646.                         result = PrError();
  647.                         HUnlock ((Handle) gMonitorPICT);
  648.                     }
  649.                     break;
  650.                 }
  651.                 case kQuitItem:
  652.                 {
  653.                     // Let's scram
  654.                     DoQuit();
  655.                     break;
  656.                 }
  657.             }
  658.             break;
  659.         }
  660.         case kEditID:
  661.         {
  662.             // Is this a DA kind of thing?
  663.             if (!SystemEdit (menuItem - 1))
  664.             {
  665.                 // We only do cut and copy
  666.                 if ((menuItem == kCutItem) || (menuItem == kCopyItem))
  667.                 {
  668.                     // Copy a frame from the monitor
  669.                     if (gMonitorPICT != nil)
  670.                     {
  671.                         KillPicture (gMonitorPICT);
  672.                     }
  673.                     gMonitorPICT = nil;
  674.                     result = SGGrabPict (gSeqGrabber, &gMonitorPICT, nil, 0, grabPictOffScreen);
  675.                     if ((result == noErr) && (gMonitorPICT != nil))
  676.                     {
  677.                         result = ZeroScrap();
  678.                         HLock ((Handle) gMonitorPICT);
  679.                         result = PutScrap (GetHandleSize ((Handle) gMonitorPICT), 'PICT', *(Handle)gMonitorPICT);
  680.                         HUnlock ((Handle) gMonitorPICT);
  681.                         if (result != noErr)
  682.                         {
  683.                             // Cut or copy failed, probably due to lack of memory
  684.                         }
  685.                     }
  686.                 }
  687.             }
  688.             break;
  689.         }
  690.         case kMonitorID:
  691.         {
  692.             switch (menuItem)
  693.             {
  694.                 short        width;
  695.                 short        height;
  696.                 Rect        curBounds;
  697.                 Rect        curVideoRect;
  698.                 Rect        newVideoRect;
  699.                 Rect        newBounds;
  700.                 Rect        maxBoundsRect;
  701.                 GrafPtr        savedPort;
  702.                 RgnHandle    deadRgn;
  703.                 Rect        boundsRect;
  704.                     
  705.                 case kVideoSettingsItem:
  706.                 {
  707.                     if ((gSeqGrabber != 0L) && (gVideoChannel != 0L))
  708.                     {
  709.                         Rect    newActiveVideoRect;
  710.                         Rect    adjustedActiveVideoRect;
  711.                         
  712.                         // Get our current state
  713.                         result = SGGetChannelBounds (gVideoChannel, &curBounds);
  714.                         result = SGGetVideoRect (gVideoChannel, &curVideoRect);
  715.                         
  716.                         // Pause
  717.                         result = SGPause (gSeqGrabber, true);
  718.                         
  719.                         // Do the dialog thang
  720.                         result = SGSettingsDialog (gSeqGrabber, gVideoChannel, 0, 
  721.                             nil, 0L, SeqGrabberModalFilterProc, (long) StripAddress ((Ptr) gMonitor));
  722.                             
  723.                         // What happened?
  724.                         result = SGGetVideoRect (gVideoChannel, &newVideoRect);
  725.                         result = SGGetSrcVideoBounds (gVideoChannel, &newActiveVideoRect);
  726.  
  727.                         // Set up our port
  728.                         GetPort (&savedPort);
  729.                         SetPort (gMonitor);
  730.                         
  731.                         // Has our active rect changed?
  732.                         // If so, it's because our video standard changed (e.g., NTSC to PAL),
  733.                         // and we need to adjust our monitor window
  734.                         if (!EqualRect (&gActiveVideoRect, &newActiveVideoRect))
  735.                         {
  736.                             if (gFullSize)
  737.                             {
  738.                                 width = newActiveVideoRect.right - newActiveVideoRect.left;
  739.                                 height = newActiveVideoRect.bottom - newActiveVideoRect.top;
  740.                                 
  741.                                 gActiveVideoRect = newActiveVideoRect;
  742.                                 SizeWindow (gMonitor, width, height, false);
  743.                                 result = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  744.                             }
  745.                             else if (gHalfSize)
  746.                             {
  747.                                 width = (newActiveVideoRect.right - newActiveVideoRect.left) / 2;
  748.                                 height = (newActiveVideoRect.bottom - newActiveVideoRect.top) / 2;
  749.                                 
  750.                                 gActiveVideoRect = newActiveVideoRect;
  751.                                 SizeWindow (gMonitor, width, height, false);
  752.                                 result = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  753.                             }
  754.                             else if (gQuarterSize)
  755.                             {
  756.                                 width = (newActiveVideoRect.right - newActiveVideoRect.left) / 4;
  757.                                 height = (newActiveVideoRect.bottom - newActiveVideoRect.top) / 4;
  758.                                 
  759.                                 gActiveVideoRect = newActiveVideoRect;
  760.                                 SizeWindow (gMonitor, width, height, false);
  761.                                 result = SGSetChannelBounds (gVideoChannel, &(gMonitor->portRect));
  762.                             }
  763.                         }
  764.                         
  765.                         // Has our crop changed?
  766.                         // This code shows how to be crop video panel friendly
  767.                         // Two important things - 
  768.                         // 1) Be aware that you might have been cropped and adjust your
  769.                         //    video window appropriately
  770.                         // 2) Be aware that you might have been adjusted and attempt to
  771.                         //    account for this.  Adjusting refers to using the digitizer
  772.                         //    rect to "adjust" the active source rect within the maximum
  773.                         //    source rect.  This is useful if you're getting those nasty
  774.                         //    black bands on the sides of your video display - you can use
  775.                         //    the control-arrow key sequence to shift the active source 
  776.                         //    rect around when you're in the crop video panel
  777.                         
  778.                         adjustedActiveVideoRect = gActiveVideoRect;
  779.                         if (!EqualRect (&curVideoRect, &newVideoRect))
  780.                         {
  781.                             if ((newVideoRect.left < gActiveVideoRect.left) ||
  782.                                 (newVideoRect.right > gActiveVideoRect.right) ||
  783.                                 (newVideoRect.top < gActiveVideoRect.top) ||
  784.                                 (newVideoRect.bottom > gActiveVideoRect.bottom))
  785.                             {
  786.                                 if (newVideoRect.left < gActiveVideoRect.left)
  787.                                 {
  788.                                     adjustedActiveVideoRect.left = newVideoRect.left;
  789.                                     adjustedActiveVideoRect.right -= (gActiveVideoRect.left - newVideoRect.left);
  790.                                 }
  791.                                 if (newVideoRect.right > gActiveVideoRect.right)
  792.                                 {
  793.                                     adjustedActiveVideoRect.right = newVideoRect.right;
  794.                                     adjustedActiveVideoRect.left += (newVideoRect.right - gActiveVideoRect.right);
  795.                                 }
  796.                                 if (newVideoRect.top < gActiveVideoRect.top)
  797.                                 {
  798.                                     adjustedActiveVideoRect.top = newVideoRect.top;
  799.                                     adjustedActiveVideoRect.bottom -= (gActiveVideoRect.top - newVideoRect.top);
  800.                                 }
  801.                                 if (newVideoRect.bottom > gActiveVideoRect.bottom)
  802.                                 {
  803.                                     adjustedActiveVideoRect.bottom = newVideoRect.bottom;
  804.                                     adjustedActiveVideoRect.top += (newVideoRect.bottom - gActiveVideoRect.bottom);
  805.                                 }
  806.                                 newBounds = newVideoRect;
  807.                                 MapRect (&newBounds, &adjustedActiveVideoRect, &(gMonitor->portRect));
  808.                             }
  809.                             else    // Can't tell if we've been adjusted (digitizer rect is smaller on all sides
  810.                                     // than the active source rect)
  811.                             {
  812.                                 newBounds = newVideoRect;
  813.                                 MapRect (&newBounds, &gActiveVideoRect, &(gMonitor->portRect));
  814.                             }
  815.                             width = newBounds.right - newBounds.left;
  816.                             height = newBounds.bottom - newBounds.top;
  817.                             result = SGSetChannelBounds (gVideoChannel, &newBounds);
  818.                         }
  819.  
  820.                         // Clean out the part of the port that isn't being drawn in
  821.                         deadRgn = NewRgn();
  822.                         if (deadRgn != nil)
  823.                         {
  824.                             result = SGGetChannelBounds (gVideoChannel, &boundsRect);
  825.                             result = XorRectToRgn (&boundsRect, &(gMonitor->portRect), &deadRgn);
  826.                             EraseRgn (deadRgn);
  827.                             DisposeRgn (deadRgn);
  828.                         }
  829.  
  830.                         SetPort (savedPort);
  831.                         
  832.                         // The pause that refreshes
  833.                         result = SGPause (gSeqGrabber, false);
  834.                     }
  835.                     break;
  836.                 }
  837.                 case kSoundSettingsItem:
  838.                 {
  839.                     if ((gSeqGrabber != 0L) && (gSoundChannel != 0L))
  840.                     {
  841.                         // Do the dialog thang
  842.                         result = SGSettingsDialog (gSeqGrabber, gSoundChannel, 0,
  843.                             nil, 0L, SeqGrabberModalFilterProc, (long) StripAddress ((Ptr) gMonitor));
  844.                     }
  845.                     break;
  846.                 }
  847.                 case kQuarterSizeItem:
  848.                 {
  849.                     // New width and height
  850.                     width = (gActiveVideoRect.right - gActiveVideoRect.left) / 4;
  851.                     height = (gActiveVideoRect.bottom - gActiveVideoRect.top) / 4;
  852.                     
  853.                     // Set flags and menus
  854.                     gQuarterSize = true;
  855.                     gHalfSize = false;
  856.                     gFullSize = false;
  857.                     AdjustMenus();
  858.                     
  859.                     // Resize the monitor
  860.                     GetPort (&savedPort);
  861.                     SetPort (gMonitor);
  862.                     result = SGPause (gSeqGrabber, true);
  863.                     result = SGGetChannelBounds (gVideoChannel, &curBounds);
  864.                     maxBoundsRect = gMonitor->portRect;
  865.                     SizeWindow (gMonitor, width, height, false);
  866.                     MapRect (&curBounds, &maxBoundsRect, &(gMonitor->portRect));
  867.                     result = SGSetChannelBounds (gVideoChannel, &curBounds);
  868.  
  869.                     // Clean out part of port we're not drawing in
  870.                     deadRgn = NewRgn();
  871.                     if (deadRgn != nil)
  872.                     {
  873.                         result = SGGetChannelBounds (gVideoChannel, &boundsRect);
  874.                         result = XorRectToRgn (&boundsRect, &(gMonitor->portRect), &deadRgn);
  875.                         EraseRgn (deadRgn);
  876.                         DisposeRgn (deadRgn);
  877.                     }
  878.                         
  879.                     SetPort (savedPort);
  880.                     result = SGPause (gSeqGrabber, false);
  881.                     break;
  882.                 }
  883.                 case kHalfSizeItem:
  884.                 {
  885.                     // New width and height
  886.                     width = (gActiveVideoRect.right - gActiveVideoRect.left) / 2;
  887.                     height = (gActiveVideoRect.bottom - gActiveVideoRect.top) / 2;
  888.                     
  889.                     // Set flags and menus
  890.                     gQuarterSize = false;
  891.                     gHalfSize = true;
  892.                     gFullSize = false;
  893.                     AdjustMenus();
  894.                     
  895.                     // Resize the monitor
  896.                     GetPort (&savedPort);
  897.                     SetPort (gMonitor);
  898.                     result = SGPause (gSeqGrabber, true);
  899.                     result = SGGetChannelBounds (gVideoChannel, &curBounds);
  900.                     maxBoundsRect = gMonitor->portRect;
  901.                     SizeWindow (gMonitor, width, height, false);
  902.                     MapRect (&curBounds, &maxBoundsRect, &(gMonitor->portRect));
  903.                     result = SGSetChannelBounds (gVideoChannel, &curBounds);
  904.  
  905.                     // Clean out part of port we're not drawing in
  906.                     deadRgn = NewRgn();
  907.                     if (deadRgn != nil)
  908.                     {
  909.                         result = SGGetChannelBounds (gVideoChannel, &boundsRect);
  910.                         result = XorRectToRgn (&boundsRect, &(gMonitor->portRect), &deadRgn);
  911.                         EraseRgn (deadRgn);
  912.                         DisposeRgn (deadRgn);
  913.                     }
  914.                         
  915.                     SetPort (savedPort);
  916.                     result = SGPause (gSeqGrabber, false);
  917.                     break;
  918.                 }
  919.                 case kFullSizeItem:
  920.                 {
  921.                     // New width and height
  922.                     width = gActiveVideoRect.right - gActiveVideoRect.left;
  923.                     height = gActiveVideoRect.bottom - gActiveVideoRect.top;
  924.                     
  925.                     // Set flags and menus
  926.                     gQuarterSize = false;
  927.                     gHalfSize = false;
  928.                     gFullSize = true;
  929.                     AdjustMenus();
  930.                     
  931.                     // Resize the monitor
  932.                     GetPort (&savedPort);
  933.                     SetPort (gMonitor);
  934.                     result = SGPause (gSeqGrabber, true);
  935.                     result = SGGetChannelBounds (gVideoChannel, &curBounds);
  936.                     maxBoundsRect = gMonitor->portRect;
  937.                     SizeWindow (gMonitor, width, height, false);
  938.                     MapRect (&curBounds, &maxBoundsRect, &(gMonitor->portRect));
  939.                     result = SGSetChannelBounds (gVideoChannel, &curBounds);
  940.  
  941.                     // Clean out part of port we're not drawing in
  942.                     deadRgn = NewRgn();
  943.                     if (deadRgn != nil)
  944.                     {
  945.                         result = SGGetChannelBounds (gVideoChannel, &boundsRect);
  946.                         result = XorRectToRgn (&boundsRect, &(gMonitor->portRect), &deadRgn);
  947.                         EraseRgn (deadRgn);
  948.                         DisposeRgn (deadRgn);
  949.                     }
  950.                         
  951.                     SetPort (savedPort);
  952.                     result = SGPause (gSeqGrabber, false);
  953.                     break;
  954.                 }
  955.                 case kRecordItem:
  956.                 {
  957.                     FSSpec    theFSSpec;
  958.                     long    savedDirID = *(long *) CurDirStore;
  959.                     long    dirID;
  960.                     short    savedVRefNum = *(short *) SFSaveDisk;
  961.                     short    vRefNum;
  962.                     
  963.                     result = FindFolder (kOnSystemDisk, kDesktopFolderType, kCreateFolder,
  964.                         &vRefNum, &dirID);
  965.                     *(short *)SFSaveDisk = -vRefNum;
  966.                     *(long *)CurDirStore = dirID;
  967.                     
  968.                     result = FSMakeFSSpec (vRefNum, dirID, "\pHack MooV", &theFSSpec);
  969.                     result = DeleteMovieFile (&theFSSpec);
  970.                     result = CreateMovieFile (&theFSSpec, 'TVOD', smSystemScript,
  971.                         createMovieFileDontOpenFile | createMovieFileDontCreateMovie,
  972.                         nil, nil);
  973.                     result = SGStop (gSeqGrabber);
  974.                     result = SGSetDataOutput (gSeqGrabber, &theFSSpec, seqGrabToDisk);
  975.                     result = SGStartRecord (gSeqGrabber);
  976.                     while (!Button() && (result == noErr))
  977.                     {
  978.                         result = SGIdle (gSeqGrabber);
  979.                     }
  980.                     result = SGStop (gSeqGrabber);
  981.                     result = SGStartPreview (gSeqGrabber);
  982.                     
  983.                     *(short *)SFSaveDisk = savedVRefNum;
  984.                     *(long *)CurDirStore = savedDirID;
  985.                     break;
  986.                 }
  987.                 default:
  988.                 {
  989.                     break;
  990.                 }
  991.             }
  992.         }
  993.         default:
  994.         {
  995.             break;
  996.         }
  997.     }
  998. }
  999.  
  1000. //-----------------------------------------------------------------------
  1001.  
  1002. static void
  1003. DoAboutDialog (void)
  1004. {
  1005.     short        itemHit;
  1006.     short        itemType;
  1007.     Handle        itemHandle;
  1008.     Rect        itemRect;
  1009.     DialogPtr    aboutDialog = GetNewDialog (kAboutDLOGID, nil, (WindowPtr)-1L);
  1010.  
  1011.     // Do the boring about dialog
  1012.     GetDItem (aboutDialog, kAboutOKButtonOutline, &itemType, &itemHandle, &itemRect);
  1013.     SetDItem (aboutDialog, kAboutOKButtonOutline, itemType, 
  1014.         (Handle) AboutDrawProc, &itemRect);
  1015.  
  1016.     ShowWindow (aboutDialog);
  1017.     do
  1018.     {
  1019.         ModalDialog (nil, &itemHit);
  1020.     }
  1021.     while (itemHit != kAboutOKButton);
  1022.     DisposDialog (aboutDialog);
  1023. }
  1024.  
  1025. //-----------------------------------------------------------------------
  1026.  
  1027. pascal void
  1028. AboutDrawProc (DialogPtr theDialog, short theItemNum)
  1029. {
  1030.     PenState    thePenState;
  1031.     OSErr        result = noErr;
  1032.     Rect        itemRect;
  1033.     Handle        itemHandle;
  1034.     short        itemType;
  1035.     
  1036.     // Set up the pen
  1037.     GetPenState (&thePenState);
  1038.     
  1039.     GetDItem (theDialog, theItemNum, &itemType, &itemHandle, &itemRect);
  1040.     
  1041.     // What item do we need to draw?
  1042.     switch (theItemNum)
  1043.     {
  1044.         case kAboutOKButtonOutline:
  1045.             PenNormal();
  1046.             PenMode (patCopy);
  1047.             PenSize (3, 3);
  1048.             InsetRect (&itemRect, -4, -4);
  1049.             FrameRoundRect (&itemRect, 16, 16);
  1050.             break;
  1051.         default:
  1052.             break;
  1053.     }
  1054.     
  1055.     // Restore the pen
  1056.     SetPenState (&thePenState);
  1057. }
  1058.  
  1059. //-----------------------------------------------------------------------
  1060.  
  1061. static OSErr
  1062. XorRectToRgn (Rect *srcRectA, Rect *srcRectB, RgnHandle *destRgn)
  1063. {
  1064.     RgnHandle    srcRgnA = NewRgn();
  1065.     RgnHandle    srcRgnB = NewRgn();
  1066.     OSErr        result = noErr;
  1067.     
  1068.     if ((destRgn != nil) && (*destRgn != nil))
  1069.     {
  1070.         if ((srcRgnA != nil) &&
  1071.             (srcRgnB != nil))
  1072.         {
  1073.             RectRgn (srcRgnA, srcRectA);
  1074.             RectRgn (srcRgnB, srcRectB);
  1075.             XorRgn (srcRgnA, srcRgnB, *destRgn);
  1076.             DisposeRgn (srcRgnA);
  1077.             DisposeRgn (srcRgnB);
  1078.         }
  1079.         else
  1080.         {
  1081.             result = memFullErr;
  1082.         }
  1083.     }
  1084.     else
  1085.     {
  1086.         result = nilHandleErr;
  1087.     }
  1088.     return (result);
  1089. }
  1090.  
  1091. //-----------------------------------------------------------------------
  1092.  
  1093. pascal Boolean
  1094. SeqGrabberModalFilterProc (DialogPtr theDialog, EventRecord *theEvent,
  1095.     short *itemHit, long refCon)
  1096. {
  1097.     // Ordinarily, if we had multiple windows we cared about, we'd handle
  1098.     // updating them in here, but since we don't, we'll just clear out
  1099.     // any update events meant for us
  1100.     
  1101.     Boolean    handled = false;
  1102.     
  1103.     if ((theEvent->what == updateEvt) && 
  1104.         ((WindowPtr) theEvent->message == (WindowPtr) refCon))
  1105.     {
  1106.         BeginUpdate ((WindowPtr) refCon);
  1107.         EndUpdate ((WindowPtr) refCon);
  1108.         handled = true;
  1109.     }
  1110.     return (handled);
  1111. }
  1112.  
  1113. //-----------------------------------------------------------------------
  1114.  
  1115. static Boolean
  1116. HasQuickTime15 (void)
  1117. {
  1118.     long    result;
  1119.     OSErr    err = Gestalt (gestaltQuickTime, &result);
  1120.     
  1121.     return (((err == noErr) & (result >= 0x0150)) ? true: false);
  1122. }
  1123.  
  1124. //-----------------------------------------------------------------------
  1125.  
  1126. static void
  1127. DoQuit (void)
  1128. {
  1129.     ComponentResult    result = noErr;
  1130.     
  1131.     // Clean up
  1132.     if (gSeqGrabber != 0L)
  1133.     {
  1134.         result = CloseComponent (gSeqGrabber);
  1135.         gSeqGrabber = 0L;
  1136.     }    
  1137.     
  1138.     if (gMonitor != nil)
  1139.     {
  1140.         DisposeWindow (gMonitor);
  1141.     }
  1142.     
  1143.     // Set quit flag
  1144.     gQuitFlag = true;
  1145.     
  1146.     ExitMovies();
  1147. }
  1148.  
  1149. //-----------------------------------------------------------------------
  1150.  
  1151.